package com.hmdp.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hmdp.dto.Result;
import com.hmdp.dto.UserDTO;
import com.hmdp.entity.Follow;
import com.hmdp.entity.User;
import com.hmdp.entity.UserInfo;
import com.hmdp.mapper.FollowMapper;
import com.hmdp.service.IFollowService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.service.IUserInfoService;
import com.hmdp.service.IUserService;
import com.hmdp.utils.UserHolder;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.hmdp.constants.RedisConstants.USER_FOLLOW_KEY;


@Service
public class FollowServiceImpl extends ServiceImpl<FollowMapper, Follow> implements IFollowService {


    @Resource
    private FollowMapper followMapper;

    @Resource
    private IUserService iUserService;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private IUserInfoService iUserInfoService;

    @Override
    public Result isFollow(Long blogUserId) {

        Long loginUserId = UserHolder.getUser().getId();

        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Follow::getUserId, loginUserId).eq(Follow::getFollowUserId, blogUserId);

        //查询登录用户是否关注博主
        Follow follow = this.getOne(queryWrapper);
        //true 关注了 未关注
        return Result.ok(follow != null);
    }

    @Override
    @Transactional
    public Result follow(Long id, Boolean followed) {

        //获取当前登录用户id
        Long loginUserId = UserHolder.getUser().getId();

        //关注
        if (followed) {
            Follow follow = new Follow();
            follow.setUserId(loginUserId);
            follow.setFollowUserId(id);
            boolean saveSuccess = this.save(follow);
            if (saveSuccess) {
                //1、关注后 博主的粉丝加一
                updateFanCount(id, true);
                //2、关注后 用户的关注加一
                updateFollowCount(loginUserId, true);
                //3、存入redis中 TODO 供后续查询共同关注 交集
                stringRedisTemplate.opsForSet().add(USER_FOLLOW_KEY + loginUserId.toString(), id.toString());
            }
            return Result.ok();
        }
        //取消关注
        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Follow::getUserId, loginUserId).eq(Follow::getFollowUserId, id);
        boolean removeSuccess = this.remove(queryWrapper);
        if (removeSuccess) {
            //1、关注后 博主的粉丝减一
            updateFanCount(id, false);
            //2、关注后 用户的关注减一
            updateFollowCount(loginUserId, false);

            stringRedisTemplate.opsForSet().remove(USER_FOLLOW_KEY + loginUserId.toString(), id.toString());
        }
        return Result.ok();
    }

    private void updateFanCount(Long id, Boolean isFollow) {

        UserInfo userInfo = iUserInfoService.getById(id);
        //关注 粉丝数加1
        if (isFollow) {

            if (userInfo == null) {
                userInfo = new UserInfo();
                userInfo.setUserId(id);
                userInfo.setFans(1);
                //保存
                iUserInfoService.save(userInfo);
            } else {
                Integer fans = userInfo.getFans();
                userInfo.setFans(fans + 1);
                //更新
                iUserInfoService.updateById(userInfo);
            }
        } else {
            //取关粉丝减1
            Integer fans = userInfo.getFans();
            userInfo.setFans(fans - 1);
            iUserInfoService.updateById(userInfo);
        }
    }

    private void updateFollowCount(Long id, Boolean isFollow) {

        UserInfo userInfo = iUserInfoService.getById(id);
        //关注 关注数加1
        if (isFollow) {

            if (userInfo == null) {
                userInfo = new UserInfo();
                userInfo.setUserId(id);
                userInfo.setFollowee(1);
                //保存
                iUserInfoService.save(userInfo);
            } else {
                Integer followee = userInfo.getFollowee();
                userInfo.setFollowee(followee + 1);
                //更新
                iUserInfoService.updateById(userInfo);
            }
        } else {
            //取关 关注数减1
            Integer followee = userInfo.getFollowee();
            userInfo.setFollowee(followee - 1);
            iUserInfoService.updateById(userInfo);
        }
    }

    @Override
    public Result followCommons(Long id) {

        //获取当前登录用户id
        Long loginUserId = UserHolder.getUser().getId();

        //TODO 1、MySQL查询共同关注(1、子查询 2、内连接)
        //List<UserDTO> commonUsers = mysqlGet(id, loginUserId);

        //TODO 2、Redis查询共同关注(Set )
        List<UserDTO> commonUsers = redisGet(id, loginUserId);

        return Result.ok(commonUsers);
    }


    @Override
    public Result queryFanList() {

        Long id = UserHolder.getUser().getId();

        LambdaQueryWrapper<Follow> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(Follow::getFollowUserId, id)
                .select(Follow::getUserId)
                .last("LIMIT 10");

        //从follow表中获取粉丝id
        List<Follow> fanIds = this.list(queryWrapper);

        //获取粉丝信息
        List<UserDTO> fanList = fanIds.stream().map(follow -> {
            User user = iUserService.getById(follow.getUserId());
            return BeanUtil.copyProperties(user, UserDTO.class);
        }).collect(Collectors.toList());

        return Result.ok(fanList);
    }


    private List<UserDTO> redisGet(Long id, Long loginUserId) {

        Set<String> userIds = stringRedisTemplate.opsForSet().intersect(
                USER_FOLLOW_KEY + loginUserId.toString(),
                USER_FOLLOW_KEY + id.toString());
        if (userIds == null || userIds.isEmpty()) {
            // 无交集
            return Collections.emptyList();
        }
        List<UserDTO> commonUsers = userIds.stream().map(userId -> {
            //根据用户id获取用户信息
            User user = iUserService.getById(userId);
            return BeanUtil.copyProperties(user, UserDTO.class);
        }).collect(Collectors.toList());
        return commonUsers;
    }

    private List<UserDTO> mysqlGet(Long id, Long loginUserId) {

        List<Long> userIds = followMapper.followCommons2(loginUserId, id);
        if (userIds == null || userIds.isEmpty()) {
            // 无交集
            return Collections.emptyList();
        }
        List<UserDTO> commonUsers = userIds.stream().map(userId -> {
            //根据用户id获取用户信息
            User user = iUserService.getById(userId);
            return BeanUtil.copyProperties(user, UserDTO.class);
        }).collect(Collectors.toList());
        return commonUsers;
    }
}
